package com.gitee.fufu669.utils;

import com.gitee.fufu669.aspect.Logging;
import com.gitee.fufu669.utils.vo.SwaggerApiDocsVo;
import io.swagger.annotations.ApiParam;
import org.apache.poi.xwpf.model.XWPFHeaderFooterPolicy;
import org.apache.poi.xwpf.usermodel.*;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestParam;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.OutputStream;
import java.math.BigInteger;
import java.util.List;
import java.util.Map;

public class CacheSwaggerToWikiUtil implements Logging {

    public static final Logger logger = LoggerFactory.getLogger(CacheSwaggerToWikiUtil.class);

    public static void info(
            @ApiParam(value = "serverUrl，比如你的swagger地址是http://192.168.22.183:5000/swagger-ui.html，那么这里就填入http://192.168.22.183:5000") @RequestParam(value = "serverUrl", required = false, defaultValue = "http://localhost:10666") String serverUrl,
            @ApiParam(value = "showServerUrl，用来展示在wiki中的服务器的路径，比如http://www.test.com") @RequestParam(value = "showServerUrl", required = false, defaultValue = "http://localhost:10666") String showServerUrl,
            HttpServletRequest request,
            HttpServletResponse response
    ) {
        String swaggerUrl = serverUrl+"/v2/api-docs";
        getSwagger(swaggerUrl,showServerUrl,request,response);
    }

    public static void getSwagger(String swaggerUrl, String showServerUrl, HttpServletRequest request, HttpServletResponse response) {
        String swaggerString = CacheHttpUtil.get(swaggerUrl);
        if (StringUtils.isEmpty(swaggerString)) {
            return;
        }
        swaggerString = swaggerString.replaceAll("\\$ref", "ref");
        //logger.info(swaggerString);
        SwaggerApiDocsVo swaggerApiDocsVo = CacheJsonUtil.toObject(swaggerString, SwaggerApiDocsVo.class);
        try {
            XWPFDocument xwpfDocument = new XWPFDocument();
            // 创建Word文件
            CTSectPr sectPr = xwpfDocument.getDocument().getBody().addNewSectPr();
            XWPFHeaderFooterPolicy policy = new XWPFHeaderFooterPolicy(xwpfDocument, sectPr);
            //添加页眉
            CTP ctpHeader = CTP.Factory.newInstance();
            CTR ctrHeader = ctpHeader.addNewR();
            CTText ctHeader = ctrHeader.addNewT();
            String headerText = "swagger";
            ctHeader.setStringValue(headerText);
            XWPFParagraph headerParagraph = new XWPFParagraph(ctpHeader, xwpfDocument);
            //设置为右对齐
            headerParagraph.setAlignment(ParagraphAlignment.RIGHT);
            XWPFParagraph[] parsHeader = new XWPFParagraph[1];
            parsHeader[0] = headerParagraph;
            policy.createHeader(XWPFHeaderFooterPolicy.DEFAULT, parsHeader);
            //添加页脚
            CTP ctpFooter = CTP.Factory.newInstance();
            CTR ctrFooter = ctpFooter.addNewR();
            CTText ctFooter = ctrFooter.addNewT();
            String footerText = "swagger";
            ctFooter.setStringValue(footerText);
            XWPFParagraph footerParagraph = new XWPFParagraph(ctpFooter, xwpfDocument);
            headerParagraph.setAlignment(ParagraphAlignment.CENTER);
            XWPFParagraph[] parsFooter = new XWPFParagraph[1];
            parsFooter[0] = footerParagraph;
            policy.createFooter(XWPFHeaderFooterPolicy.DEFAULT, parsFooter);

            String topTitle = swaggerApiDocsVo.getInfo().getTitle();
            writeBoldText(xwpfDocument, topTitle, 26, "Heading1");
            String topDescription = swaggerApiDocsVo.getInfo().getDescription();
            writeText(xwpfDocument, topDescription, 6);
            Map<String, Object> mapLicense = swaggerApiDocsVo.getInfo().getLicense();
            Map<String, Object> definitions = (Map) swaggerApiDocsVo.getDefinitions();
            writeText(xwpfDocument, "协议: " + mapLicense.get("name") + " " + mapLicense.get("url"), 6);
            writeText(xwpfDocument, "版本: " + swaggerApiDocsVo.getInfo().getVersion(), 6);
            writeText(xwpfDocument, "服务需知: " + swaggerApiDocsVo.getInfo().getTermsOfService(), 6);
            writeText(xwpfDocument, "swagger版本: " + swaggerApiDocsVo.getSwagger(), 6);

            writeAllDefinitions(xwpfDocument, definitions);
            Integer index = 1;
            for (SwaggerApiDocsVo.Tag tag : swaggerApiDocsVo.getTags()) {
                writeText(xwpfDocument, "", 6);
                index += 1;
                writeBoldText(xwpfDocument, index + ".0 " + "Controller: " + tag.getName(), 12, "Heading2");
                writeBoldText(xwpfDocument, "功能描述: " + tag.getDescription(), 12, null);
                writeText(xwpfDocument, "", 6);
                Integer subIndex = 0;
                for (Map.Entry<String, Object> entry : swaggerApiDocsVo.getPaths().entrySet()) {
                    Map<String, Object> getPostValue = (Map) entry.getValue();
                    for (Map.Entry<String, Object> entryGetPostValue : getPostValue.entrySet()) {
                        Map<String, Object> getPostValueDetail = (Map) entryGetPostValue.getValue();
                        List<String> tags = (List) getPostValueDetail.get("tags");
                        if (tags.contains(tag.getName())) {
                            subIndex += 1;
                            writeBoldText(xwpfDocument, index + "." + subIndex + " 接口路径: " + (StringUtils.isEmpty(showServerUrl) ? "http://"+ swaggerApiDocsVo.getHost():showServerUrl) + entry.getKey(), 8, "Heading3");
                            writeText(xwpfDocument, "方法类型: " + entryGetPostValue.getKey(), 6);
                            writeText(xwpfDocument, "消费类型: " + CacheJsonUtil.toJson(getPostValueDetail.get("consumes")), 6);
                            writeText(xwpfDocument, "生产类型: " + CacheJsonUtil.toJson(getPostValueDetail.get("produces")), 6);
                            writeText(xwpfDocument, "接口描述: " + getPostValueDetail.get("summary"), 6);
                            //参数列表
                            //parameters
                            writeParams(xwpfDocument, getPostValueDetail);
                            writeBoldText(xwpfDocument, "出参: ", 7, null);
                            Map<String, Object> responseMap = (Map) getPostValueDetail.get("responses");
                            writeOutPutResponse(xwpfDocument, responseMap, definitions);
                            writeBoldText(xwpfDocument, "返回详情: ", 7, null);
                            writeResponseDetail(xwpfDocument, responseMap, definitions);
                            writeText(xwpfDocument, "", 6);
                        }
                    }
                }
            }
            //xwpfDocument.createTOC();
            try {
                response.setCharacterEncoding("utf-8");
                //                response.setContentType("multipart/form-data");
                response.setContentType("application/x-download");
                response.setHeader("Content-Disposition", "attachment;filename=swagger_to_wiki_" + CachePasswordUtil.generateTokenNumberMilliSeconds() + ".doc");
                response.addHeader("Pargam", "no-cache");
                response.addHeader("Cache-Control", "no-cache");
            } catch (Exception ex) {
                ex.printStackTrace();
            }
            OutputStream outputStream = response.getOutputStream();
            xwpfDocument.write(outputStream);
            outputStream.flush();
            outputStream.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void  writeAllDefinitions(XWPFDocument xwpfDocument, Map<String, Object> definitions) {
        writeText(xwpfDocument, "", 6);
        writeBoldText(xwpfDocument, "1.0 所有对象的定义", 12, "Heading2");
        if (definitions == null) {
            return;
        }
        int subIndex = 1;
        for (Map.Entry<String, Object> entry : definitions.entrySet()) {
            if (!entry.getKey().contains("单值返回")) {
                writeText(xwpfDocument, "", 6);
                writeBoldText(xwpfDocument, "1." + subIndex + " " + entry.getKey(), 7, "Heading3");
                writeDefinitions(xwpfDocument, (Map) entry.getValue());
                subIndex += 1;
            }
        }
        writeText(xwpfDocument, "", 6);
    }

    public static void  writeParams(XWPFDocument xwpfDocument, Map getPostValueDetail) {
        List<Map> parameters = (List) getPostValueDetail.get("parameters");
        if (parameters != null) {
            writeBoldText(xwpfDocument, "入参: ", 7, null);
            XWPFTable xwpfTable = xwpfDocument.createTable(parameters.size() + 1, 5);
            //创建一个表格
            CTTblPr ctTblPr = xwpfTable.getCTTbl().addNewTblPr();
            //表格属性
            CTTblWidth ctTblWidth = ctTblPr.addNewTblW();
            ctTblWidth.setW(BigInteger.valueOf(8000));
            //表格宽度
            ctTblWidth.setType(STTblWidth.DXA);
            //设置表格宽度为非自动

            //表头
            xwpfTable.getRow(0).getCell(0).setParagraph(getXWPFParagraphBold("参数名称name", 6));
            xwpfTable.getRow(0).getCell(1).setParagraph(getXWPFParagraphBold("参数位置in", 6));
            xwpfTable.getRow(0).getCell(2).setParagraph(getXWPFParagraphBold("参数类型type", 6));

            //xwpfTable.getRow(0).getCell(3).setParagraph(getXWPFParagraphBold("是否必须required", 6));
            xwpfTable.getRow(0).getCell(3).setParagraph(getXWPFParagraphBold("参数描述description", 6));
            xwpfTable.getRow(0).getCell(4).setParagraph(getXWPFParagraphBold("参数引用ref", 6));
            int i = 1;
            /*表内容*/
            for (Map parameter : parameters) {
                xwpfTable.getRow(i).getCell(0).setParagraph(getXWPFParagraph("" + (parameter.get("name") == null ? "" : parameter.get("name")), 6));
                xwpfTable.getRow(i).getCell(1).setParagraph(getXWPFParagraph("" + (parameter.get("in") == null ? "" : parameter.get("in")), 6));
                String type = (String) parameter.get("type");
                String ref = "";
                if (type == null) {
                    Map schema = (Map) parameter.get("schema");
                    type = CacheJsonUtil.toJson(schema);
                    if (schema.get("ref") != null) {
                        ref = (String) schema.get("ref");
                        type = "";
                        ref = ref.replaceAll("#/definitions/", "");
                    }
                } else {
                    if (parameter.get("items") != null) {
                        type += " " + CacheJsonUtil.toJson(parameter.get("items"));
                    }
                }
                xwpfTable.getRow(i).getCell(2).setParagraph(getXWPFParagraph(type, 6));

                //xwpfTable.getRow(i).getCell(3).setParagraph(getXWPFParagraph("" + (parameter.get("required")==null?"":parameter.get("required")), 6));
                xwpfTable.getRow(i).getCell(3).setParagraph(getXWPFParagraph("" + (parameter.get("description") == null ? "" : parameter.get("description")), 6));
                xwpfTable.getRow(i).getCell(4).setParagraph(getXWPFParagraph(ref, 6));
                i += 1;
            }
        }
    }

    public static void  writeOutPutResponse(XWPFDocument xwpfDocument, Map<String, Object> responseMap, Map definitions) {
        int rows = 0;
        for (Map.Entry<String, Object> stringObjectEntry : responseMap.entrySet()) {
            rows = rows + 1;
        }
        XWPFTable xwpfTable = xwpfDocument.createTable(rows + 1, 2);
        //创建一个表格
        CTTblPr ctTblPr = xwpfTable.getCTTbl().addNewTblPr();
        //表格属性
        CTTblWidth ctTblWidth = ctTblPr.addNewTblW();
        ctTblWidth.setW(BigInteger.valueOf(8000));
        //表格宽度
        ctTblWidth.setType(STTblWidth.DXA);
        //设置表格宽度为非自动

        //表头
        xwpfTable.getRow(0).getCell(0).setParagraph(getXWPFParagraphBold("状态码Http Status Code", 6));
        xwpfTable.getRow(0).getCell(1).setParagraph(getXWPFParagraphBold("描述description", 6));
        int i = 0;
        for (Map.Entry<String, Object> stringObjectEntry : responseMap.entrySet()) {
            i = i + 1;
            Map<String, Object> descriptionSchemeMap = (Map) stringObjectEntry.getValue();
            String key = stringObjectEntry.getKey();
            XWPFParagraph xwpfParagraph = getXWPFParagraph(key, 6);
            xwpfTable.getRow(i).getCell(0).setParagraph(xwpfParagraph);
            xwpfTable.getRow(i).getCell(1).setParagraph(getXWPFParagraph("" + (descriptionSchemeMap.get("description") == null ? "" : descriptionSchemeMap.get("description")), 6));
        }
    }

    public static void  writeResponseDetail(XWPFDocument xwpfDocument, Map<String, Object> responseMap, Map<String, Object> definitions) {
        int rows = 3;
        int i = 1;
        Map<String, Object> descriptionSchemeMap = (Map) responseMap.get("200");
        if (descriptionSchemeMap.get("schema") != null) {
            Map<String, Object> schema = (Map) descriptionSchemeMap.get("schema");
            if (schema.get("ref") != null) {
                String schemaString = "" + schema.get("ref");

                //String schemeString = JSON.toJSONString(descriptionSchemeMap, SerializerFeature.DisableCircularReferenceDetect);
                schemaString = schemaString.replaceAll("#/definitions/", "");

                //xwpfTable.getRow(i).getCell(2).setParagraph(getXWPFParagraph(schemaString, 6));
                Map<String, Object> schemaDefinitions = (Map) definitions.get(schemaString);
                writeBoldText(xwpfDocument, schemaString, 7, null);
                writeDefinitions(xwpfDocument, schemaDefinitions);
            } else {
                writeText(xwpfDocument, CacheJsonUtil.toJson(schema), 6);
            }
        }
    }

    public static void  writeDefinitions(XWPFDocument xwpfDocument, Map<String, Object> schemaDefinitions) {
        if (schemaDefinitions != null) {
            if (schemaDefinitions.get("properties") != null) {
                Map<String, Object> properties = (Map) schemaDefinitions.get("properties");
                int rows = 0;
                for (Map.Entry<String, Object> propertiesEntry : properties.entrySet()) {
                    rows += 1;
                }
                XWPFTable xwpfTable = xwpfDocument.createTable(rows + 1, 6);
                //创建一个表格
                CTTblPr ctTblPr = xwpfTable.getCTTbl().addNewTblPr();
                //表格属性
                CTTblWidth ctTblWidth = ctTblPr.addNewTblW();
                ctTblWidth.setW(BigInteger.valueOf(8000));
                //表格宽度
                ctTblWidth.setType(STTblWidth.DXA);
                //设置表格宽度为非自动

                //表头
                xwpfTable.getRow(0).getCell(0).setParagraph(getXWPFParagraphBold("名称", 6));
                xwpfTable.getRow(0).getCell(1).setParagraph(getXWPFParagraphBold("类型", 6));
                xwpfTable.getRow(0).getCell(2).setParagraph(getXWPFParagraphBold("格式", 6));
                xwpfTable.getRow(0).getCell(3).setParagraph(getXWPFParagraphBold("样例", 6));
                xwpfTable.getRow(0).getCell(4).setParagraph(getXWPFParagraphBold("说明", 6));
                xwpfTable.getRow(0).getCell(5).setParagraph(getXWPFParagraphBold("引用", 6));
                int i = 1;
                for (Map.Entry<String, Object> propertiesEntry : properties.entrySet()) {
                    Map<String, Object> propertiesEntryValueMap = (Map) propertiesEntry.getValue();
                    xwpfTable.getRow(i).getCell(0).setParagraph(getXWPFParagraph("" + propertiesEntry.getKey(), 6));
                    xwpfTable.getRow(i).getCell(1).setParagraph(getXWPFParagraph("" + (null == propertiesEntryValueMap.get("type") ? "" : propertiesEntryValueMap.get("type")), 6));
                    xwpfTable.getRow(i).getCell(2).setParagraph(getXWPFParagraph("" + (null == propertiesEntryValueMap.get("format") ? "" : propertiesEntryValueMap.get("format")), 6));
                    xwpfTable.getRow(i).getCell(3).setParagraph(getXWPFParagraph("" + (null == propertiesEntryValueMap.get("example") ? "" : propertiesEntryValueMap.get("example")), 6));
                    xwpfTable.getRow(i).getCell(4).setParagraph(getXWPFParagraph("" + (null == propertiesEntryValueMap.get("description") ? "" : propertiesEntryValueMap.get("description")), 6));
                    String ref = null;
                    ref = getRefString(propertiesEntryValueMap);
                    xwpfTable.getRow(i).getCell(5).setParagraph(getXWPFParagraph("" + ref, 6));
                    i += 1;
                }
            } else if(schemaDefinitions.get("additionalProperties") != null) {
                Map<String, Object> properties = (Map) schemaDefinitions.get("additionalProperties");
                int rows = 0;
                for (Map.Entry<String, Object> propertiesEntry : properties.entrySet()) {
                    rows += 1;
                }
                XWPFTable xwpfTable = xwpfDocument.createTable(rows + 1, 6);
                //创建一个表格
                CTTblPr ctTblPr = xwpfTable.getCTTbl().addNewTblPr();
                //表格属性
                CTTblWidth ctTblWidth = ctTblPr.addNewTblW();
                ctTblWidth.setW(BigInteger.valueOf(8000));
                //表格宽度
                ctTblWidth.setType(STTblWidth.DXA);
                //设置表格宽度为非自动
                //表头
                xwpfTable.getRow(0).getCell(0).setParagraph(getXWPFParagraphBold("名称", 6));
                xwpfTable.getRow(0).getCell(1).setParagraph(getXWPFParagraphBold("类型", 6));
                xwpfTable.getRow(0).getCell(2).setParagraph(getXWPFParagraphBold("格式", 6));
                xwpfTable.getRow(0).getCell(3).setParagraph(getXWPFParagraphBold("样例", 6));
                xwpfTable.getRow(0).getCell(4).setParagraph(getXWPFParagraphBold("说明", 6));
                xwpfTable.getRow(0).getCell(5).setParagraph(getXWPFParagraphBold("引用", 6));
                int i = 1;
                Map<String, Object> propertiesEntryValueMap = properties;
//                xwpfTable.getRow(i).getCell(0).setParagraph(getXWPFParagraph("" + propertiesEntry.getKey(), 6));
                xwpfTable.getRow(i).getCell(1).setParagraph(getXWPFParagraph("" + (null == propertiesEntryValueMap.get("type") ? "" : propertiesEntryValueMap.get("type")), 6));
                xwpfTable.getRow(i).getCell(2).setParagraph(getXWPFParagraph("" + (null == propertiesEntryValueMap.get("format") ? "" : propertiesEntryValueMap.get("format")), 6));
                xwpfTable.getRow(i).getCell(3).setParagraph(getXWPFParagraph("" + (null == propertiesEntryValueMap.get("example") ? "" : propertiesEntryValueMap.get("example")), 6));
                xwpfTable.getRow(i).getCell(4).setParagraph(getXWPFParagraph("" + (null == propertiesEntryValueMap.get("description") ? "" : propertiesEntryValueMap.get("description")), 6));
                String ref = getRefString(propertiesEntryValueMap);
                xwpfTable.getRow(i).getCell(5).setParagraph(getXWPFParagraph("" + ref, 6));
            }else{
                writeText(xwpfDocument, "" + CacheJsonUtil.toJson(schemaDefinitions), 6);
            }
        }
    }

    public static String getRefString(Map<String, Object> propertiesEntryValueMap) {
        String ref;
        if (null == propertiesEntryValueMap.get("items")) {
            if (null == propertiesEntryValueMap.get("ref")) {
                ref = "";
            } else {
                ref = "" + propertiesEntryValueMap.get("ref");
                ref = ref.replaceAll("#/definitions/", "");
            }
        } else {
            Map<String, Object> propertiesEntryValueMapRef = (Map) propertiesEntryValueMap.get("items");
            ref = "" + propertiesEntryValueMapRef.get("ref");
            ref = ref.replaceAll("#/definitions/", "");
        }
        return ref;
    }

    public static void  writeTopText(XWPFDocument xwpfDocument, String text, Integer fontsize) {
        XWPFParagraph xwpfParagraph = xwpfDocument.createParagraph();
        // 新建一个段落
        xwpfParagraph.setAlignment(ParagraphAlignment.CENTER);
        // 设置段落的对齐方式
        xwpfParagraph.setBorderBottom(Borders.DOUBLE);
        //设置下边框
        xwpfParagraph.setBorderTop(Borders.DOUBLE);
        //设置上边框
        xwpfParagraph.setBorderRight(Borders.DOUBLE);
        //设置右边框
        xwpfParagraph.setBorderLeft(Borders.DOUBLE);
        //设置左边框
        XWPFRun xwpfRun = xwpfParagraph.createRun();
        //创建段落文本
        xwpfRun.setText(text);
        xwpfRun.setFontSize(fontsize);
    }

    public static void  writeTopBoldText(XWPFDocument xwpfDocument, String text, Integer fontsize) {
        XWPFParagraph xwpfParagraph = xwpfDocument.createParagraph();
        // 新建一个段落
        xwpfParagraph.setAlignment(ParagraphAlignment.CENTER);
        // 设置段落的对齐方式
        xwpfParagraph.setBorderBottom(Borders.DOUBLE);
        //设置下边框
        xwpfParagraph.setBorderTop(Borders.DOUBLE);
        //设置上边框
        xwpfParagraph.setBorderRight(Borders.DOUBLE);
        //设置右边框
        xwpfParagraph.setBorderLeft(Borders.DOUBLE);
        //设置左边框
        XWPFRun xwpfRun = xwpfParagraph.createRun();
        //创建段落文本
        xwpfRun.setText(text);
        xwpfRun.setBold(true);
        //设置为粗体
        xwpfRun.setFontSize(fontsize);
    }

    public static void  writeText(XWPFDocument xwpfDocument, String text, Integer fontsize) {
        XWPFParagraph xwpfParagraph = xwpfDocument.createParagraph();
        // 新建一个段落
        XWPFRun xwpfRun = xwpfParagraph.createRun();
        xwpfRun.setText(text);
        xwpfRun.setFontSize(fontsize);
    }

    public static void  writeBoldText(XWPFDocument xwpfDocument, String text, Integer fontsize, String style) {
        XWPFParagraph xwpfParagraph = xwpfDocument.createParagraph();
        // 新建一个段落
        if (!StringUtils.isEmpty(style)) {
            xwpfParagraph.setStyle(style);
        }
        XWPFRun xwpfRun = xwpfParagraph.createRun();
        xwpfRun.setText(text);
        xwpfRun.setBold(true);
        //设置为粗体
        xwpfRun.setFontSize(fontsize);
    }

    public static XWPFParagraph getXWPFParagraph(String text, Integer fontsize) {
        XWPFDocument xwpfDocument1 = new XWPFDocument();
        XWPFParagraph xwpfParagraph = xwpfDocument1.createParagraph();
        // 新建一个段落
        XWPFRun xwpfRun = xwpfParagraph.createRun();
        //创建段落文本
        xwpfRun.setText(text);
        xwpfRun.setFontSize(fontsize);
        return xwpfParagraph;
    }

    public static XWPFParagraph getXWPFParagraphBold(String text, Integer fontsize) {
        XWPFDocument xwpfDocument1 = new XWPFDocument();
        XWPFParagraph xwpfParagraph = xwpfDocument1.createParagraph();
        // 新建一个段落
        XWPFRun xwpfRun = xwpfParagraph.createRun();
        //创建段落文本
        xwpfRun.setText(text);
        xwpfRun.setFontSize(fontsize);
        xwpfRun.setBold(true);
        //设置为粗体
        return xwpfParagraph;
    }

}
